﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO.Ports;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace 高速通信解决方案
{
    public partial class Form1 : Form
    {
        SerialPort serialPort1 = new SerialPort();
        ConcurrentQueue<byte[]> receiveBytesQueue = new ConcurrentQueue<byte[]>();
        public Form1()
        {
            InitializeComponent();
            serialPort1.DataReceived += SerialPort1_DataReceived;
            FindPortNameList();//寻找串口列表



        }
        private void SerialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            //Thread.Sleep(1);//一般加一个延时，这样能让缓冲区多储存一些数据
            int num = serialPort1.BytesToRead;//获取接收缓冲区中的字节数
            if (num > 0)
            {
                byte[] bytes = new byte[num];
                serialPort1.Read(bytes, 0, num);//将指定字节数数据存到数组中
                EnqueueData(bytes);//显示数据
            }
        }

        /// <summary>
        /// 寻找串口列表
        /// </summary>
        private void FindPortNameList()
        {
            try
            {
                cbx_PortNameList.Items.Clear();
                string[] portNameList = SerialPort.GetPortNames();//寻找电脑存在的端口
                if (portNameList != null && portNameList.Count() > 0)
                {
                    cbx_PortNameList.Items.AddRange(portNameList);
                    cbx_PortNameList.SelectedIndex = 0;
                }
            }
            catch (Exception)
            {
            }
        }

        /// <summary>
        /// 初始化串口
        /// </summary>
        private void InitialPort()
        {
            serialPort1.BaudRate = 9600;//设置波特率
            serialPort1.DataBits = 8;//设置数据位
            serialPort1.StopBits = StopBits.One;//设置停止位
            serialPort1.Parity = Parity.None;//设置校验位
        }


        /// <summary>
        /// 关闭串口
        /// </summary>
        /// <returns></returns>
        private bool ClosePort()
        {
            bool closeResult = false;
            try
            {
                if (serialPort1.IsOpen)
                {
                    serialPort1.Close();
                    if (serialPort1.IsOpen == false)
                    {
                        closeResult = true;
                    }
                }
                else
                {
                    closeResult = true;
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show("关闭串口失败");
            }
            return closeResult;
        }


        /// <summary>
        /// 打开串口
        /// </summary>
        /// <returns></returns>
        private bool OpenPort()
        {
            bool openResult = false;
            try
            {
                if (cbx_PortNameList.SelectedIndex >= 0)
                {
                    serialPort1.PortName = cbx_PortNameList.SelectedItem.ToString();
                    InitialPort();
                    if (serialPort1.IsOpen == false)
                    {
                        serialPort1.Open();//打开串口
                        if (serialPort1.IsOpen)
                            openResult = true;
                    }
                    else
                    {
                        serialPort1.Close();//关闭串口
                        serialPort1.Open();//打开串口
                        if (serialPort1.IsOpen)
                            openResult = true;
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show($"打开串口异常:{ex.Message }");
            }
            return openResult;
        }

        /// <summary>
        /// 更新串口打开状态
        /// </summary>
        /// <param name="isOpen"></param>
        private void UpdatePortStatus(bool isOpen)
        {
            if (isOpen)
            {
                toolStripStatusLabel_Port.Text = "串口打开";
                toolStripStatusLabel_Port.BackColor = Color.Lime;
            }
            else
            {
                toolStripStatusLabel_Port.Text = "串口关闭";
                toolStripStatusLabel_Port.BackColor = Color.Red;
            }
        }



        /// <summary>
        /// 将数据存入队列
        /// </summary>
        /// <param name="bytes"></param>
        private void EnqueueData(byte[] bytes)
        {
            try
            {
                receiveBytesQueue.Enqueue(bytes);
            }
            catch (Exception ex)
            {

            }
        }
        List<byte> allBytes = new List<byte>();

        bool startReceiveFile = false;
        int findIndex = 0;
        int headIndex = 0;
        int endIndex = 0;

        /// <summary>
        /// 处理接收数据
        /// </summary>
        private void DealReceiveData()
        {
            while (true)
            {
                try
                {
                    int count = receiveBytesQueue.Count;
                    bool result = false;
                    byte[] byteList = null;
                    for (int i = 0; i < count; i++)
                    {
                        result = receiveBytesQueue.TryDequeue(out byteList);
                        if (result)
                        {
                            allBytes.AddRange(byteList);

                            //寻找结束符的位置
                            bool getEndCharIndexResult = false;
                            int endCharIndex = GetEndCharIndex(allBytes, out getEndCharIndexResult);
                            if (getEndCharIndexResult)//找到结束符
                            {
                                DisplayData(allBytes, endCharIndex);
                            }
                        }
                    }
                }
                catch
                {

                }
            }
        }

        /// <summary>
        /// 获取0x0a这个索引，并且发送过来的报文以0x0d、0x0a作为结束符
        /// </summary>
        /// <param name="allBytes"></param>
        /// <param name="Result"></param>
        /// <returns></returns>
        private int GetEndCharIndex(List<byte> allBytes, out bool Result)
        {
            Result = false;
            byte endChar1 = 0x0d;//回车
            byte endChar2 = 0x0a;//换行

            int endChar1Index = allBytes.IndexOf(endChar1);
            int endChar2Index = allBytes.IndexOf(endChar2);
            if ((endChar2Index - endChar1Index) == 1 && endChar2Index > 0 && endChar1Index > 0)
            {
                Result = true;
                return endChar2Index;//返回结束符的位置
            }
            else
            {
                return -1;
            }
        }

        /// <summary>
        /// 根据结束符截取数据并显示数据
        /// </summary>
        /// <param name="allBytes"></param>
        /// <param name="endCharIndex"></param>
        private void DisplayData(List<byte> allBytes, int endCharIndex)
        {
            List<byte> removeBytes = allBytes.GetRange(0, endCharIndex + 1);
            allBytes.RemoveRange(0, endCharIndex + 1);

            bool result = false;
            string errorMsg = string.Empty;
            string str = Encoding.ASCII.GetString(removeBytes.ToArray ());
            this.Invoke(new Action (()=> {
                richTextBox_Receive.AppendText(str);
                richTextBox_Receive.AppendText($"{Environment.NewLine}{Environment.NewLine}");
            }));  
        }


        private void btn_Open_Click(object sender, EventArgs e)
        {
            try
            {
                if (btn_Open.Text == "打开")
                {
                    bool result = OpenPort();
                    if (result)
                    {
                        btn_Open.Text = "关闭";
                        UpdatePortStatus(true);
                    }

                }
                else
                {
                    ClosePort();
                    UpdatePortStatus(false);
                    btn_Open.Text = "打开";

                }
            }
            catch (Exception ex)
            {
                MessageBox.Show($"打开串口异常:{ex.Message }");
            }
        }


        /// <summary>
        /// 将字节数组转换成十六进制字符串
        /// </summary>
        /// <param name="byteArray"> 输入的字节数组</param>
        /// <param name="result"> 输出的结果true/false</param>
        /// <param name="errorStr">输出的信息</param>
        /// <param name="splitSt">分隔十六进制字符串的的分隔符</param>
        /// <param name="isUpper">是否转换为大写的十六进制字符串</param>
        /// <returns></returns>
        public static string ConvertByteArrayToHexStringArray(byte[] byteArray, out bool result, out string errorStr, string splitSt = " ", bool isUpper = true)
        {
            errorStr = string.Empty;
            result = false;
            string resultStr = string.Empty;
            List<string> listStr = new List<string>();

            try
            {
                foreach (byte item in byteArray)
                {
                    string str = string.Empty;
                    if (isUpper)
                    {
                        str = Convert.ToString(item, 16).ToUpper().PadLeft(2, '0');
                    }
                    else
                    {
                        str = Convert.ToString(item, 16).PadLeft(2, '0');
                    }
                    listStr.Add(str);
                }
                if (string.IsNullOrEmpty(splitSt))//如果为空或者null，则转换成""
                {
                    splitSt = "";
                }
                resultStr = string.Join(splitSt, listStr);
                result = true;
            }
            catch (Exception ex)
            {
                errorStr = ex.Message;
            }
            return resultStr;
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            Task taskReceiveFile = new Task(DealReceiveData);
            taskReceiveFile.Start();
        }
    }
}
